篇首语:本文由编程笔记#小编为大家整理,主要介绍了Redis基础认识内存式NoSQL数据库及简单使用Redis相关的知识,希望对你有一定的参考价值。
RDBMS就是关系型数据库管理系统,常见的mysql、SQL Server、Oracle就属于这种模型。∵可以体现数据之间的关系,支持事务,可以保证业务完整性和稳定性,小数据量时性能也较好,一般用作业务性数据存储系统。
但是!!!高并发时,分布式服务器的许多访问同时操作RDBMS,分分钟宕机。。。
此时就需要缓冲机制实现数据库的高并发。这些工具(Redis、HBase、MongoDB)就是NoSQL【不是字面的不是SQL,而是Not only SQL:非关系型数据库】,常用于高并发高性能场景下的数据缓存/数据库存储。
NoSQL读写速度非常快,并发量非常高,但是高并发是通过读写内存实现的,相对读写硬盘的RDBMS不稳定,对事务性的支持也不太友好。NoSQL的语法也不像SQL那么统一,每种SQL都有自己的语法和命令。
NoSQL可以实现读写分离,例如:
读请求:不读取MySQL,读取Redis;
写请求:直接写到MySQL。
由于正常情况大部分业务都是读多写少,读取不稳定但是写入稳定,总体来看稳定性影响不大,但是性能提升很大。当然必要时也可以使用另一个Redis缓冲,解决写入时的高并发。
Redis官网介绍Redis:
Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache, and message broker. Redis provides data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes, and streams. Redis has built-in replication, Lua scripting, LRU eviction, transactions, and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.
看不懂的可以看中文的。Redis有中文文档,对新手很友好:
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
网站长的差不多,直接看中文的命令指导或者从中文网站下载,都没问题。
Redis是用地球最强的C语言写的,可以操作硬件,性能很好。且是基于内存实现数据的读写,读写很快。其是分布式的,拓展性和稳定性很好。支持事务,拥有各种丰富的数据结构。
数据库用于永久性存储,大数据领域可以将高性能读写结果存储/采集在HDFS中。
缓存是临时性存储,在业务系统中缓存可以避免数据库性能不够引发的宕机。
消息中间件也就是消息队列MQ,Redis一般不用。
Redis的所有数据都是以KV键值对的形式存在的。
K作为唯一标识符,唯一标识一条数据,固定为String类型。
V真正存储数据,有多种类型(String、Hash、List、Set、Zset、BitMap、HypeLogLog)。
Redis类似Java中的Map集合:
Map<String,T> &#61; Redis存储
写就是指定KV&#xff0c;读只需要给定K。
举个栗子&#xff1a;
Key | Value类型 | Value值 | 应用场景 |
---|---|---|---|
pv_20200101 | String | 10000 | 一般用于存储单个数据指标的结果 |
person001 | Hash | name:laoer,age:20 sex female | 用于存储整个对象所有属性值 |
uv | List | 100,200,300,100,600 | 有序允许重复的集合&#xff0c;每天获取最后一个值 |
uv_20200101 | Set | userid1,userid2,userid3,userid4…… | 无序且不重复的集合&#xff0c;直接通过长度得到UV |
top10_product | Zset | 10000-牙膏,9999-玩具,9998-电视…… | 有序不可重复的集合&#xff0c;统计TopN |
user_filter | BitMap | 0101010101010000000011010 | 将一个字符串构建位&#xff0c;通过0和1来标记每一位 |
product_20200101 | HyperLogLog | productid1&#xff0c;id2…… | 类似于Set集合&#xff0c;底层实现原理不一样&#xff0c;数据量大的情况下&#xff0c;性能会更好 |
KV&#xff1a;【String&#xff0c;String】&#xff0c;类似于Java中Map集合的一条KV。
KV&#xff1a;【String&#xff0c;Map集合】&#xff1a;Map集合的嵌套&#xff0c;Map集合中的元素是无序的&#xff1a;
K V
person1 name&#61;zhangsan,age&#61;18,sex&#61;1,addr&#61;shanghai
person2 name&#61;lisi,age&#61;18,sex&#61;1,addr&#61;shanghai
KV&#xff1a;【String&#xff0c;List】&#xff1a;有序且可重复。
KV&#xff1a;【String&#xff0c;Set】&#xff1a;无序且不重复。
KV&#xff1a;【String&#xff0c;TreeMap集合】&#xff1a;Value也类似于Map集合&#xff0c;但是TreeMap是有序的Map集合&#xff0c;故Zset是有序且不可重复的。
keys&#xff1a;列举当前数据库的所有key&#xff1a;
keys * 列举所有key
keys a* 列举所有a开头的key
del K&#xff1a;删除某个key&#xff1a;
del s1 删除key&#61;s1的KV键值对
exists K&#xff1a;判断某个key是否存在&#xff1a;
exists s1 判断是否有s1这个键存在
type K&#xff1a;判断某个key对应的value的类型&#xff08;key都是String类型的&#xff0c;这条命令当然也就不是判断key自己的类型&#xff09;&#xff1a;
type s1 判断key&#61;s1的键值对的value的类型
expire K t&#xff08;过期时间&#xff09;&#xff1a;设置某个key的过期时间&#xff08;计时结束后该kv对会被自动删除&#xff09;&#xff1a;
expire s1 10 10秒后删除s1的键值对
ttl K&#xff1a;查看某个key剩余的存活时间&#xff08;倒计时场景经常用&#xff09;&#xff1a;
ttl s1 查看s1的kv对的剩余存活时间&#xff0c;删除后再次执行是负数
select N:切换数据库&#xff1a;
select 1 切换数据库为db1
move K N&#xff1a;将某个kv对移动到某个数据库中&#xff1a;
move s1 1 将&#xff08;默认db0&#xff0c;切换后为当前db&#xff09;数据库中的s1的键值对数据移动到db1中
flushdb&#xff1a;清空当前数据库的所有key。
flushall&#xff1a;清空所有数据库的所有key。
set&#xff1a;给String类型的Value的进行赋值或者更新&#xff1a;set K V
&#xff1b;
get&#xff1a;读取String类型的Value的值&#xff1a;get K
&#xff1b;
mset&#xff1a;用于批量写多个String类型的KV&#xff1a;mset K1 V1 K2 V2 ……
&#xff1b;
mget&#xff1a;用于批量读取String类型的Value&#xff1a;mget K1 K2 K3 ……
&#xff1b;
setnx&#xff1a;只能用于新增数据&#xff0c;当K不存在时可以进行新增&#xff08;搭配expire来使用&#xff0c;可以构建抢占锁&#xff09;&#xff1a;setnx K V
&#xff1b;
incr&#xff1a;用于对数值类型的字符串进行递增&#xff0c;递增1&#xff1a;incr K
&#xff1b;
incrby&#xff1a;指定对数值类型的字符串增长固定的步长&#xff1a;incrby K N
&#xff1b;
decr&#xff1a;对数值类型的数据进行递减&#xff0c;递减1&#xff1a;decr K
&#xff1b;
decrby&#xff1a;按照指定步长进行递减&#xff1a;decrby K N
&#xff1b;
incrbyfloat&#xff1a;基于浮点数递增&#xff08;C语言浮点数会丢失精度&#xff09;&#xff1a;incrbyfloat K N
&#xff1b;
strlen&#xff1a;统计字符串的长度&#xff1a;strlen K
&#xff1b;
getrange&#xff1a;用于截取字符串&#xff1a;getrange s2 startnum endnum
&#xff1b;
hset&#xff1a;用于为某个K添加一个属性&#xff1a;hset K k v
&#xff1b;
hget&#xff1a;用于获取某个K的某个属性的值&#xff1a;hget K k
&#xff1b;
hmset&#xff1a;批量的为某个K赋予新的属性&#xff1a;hmset K k1 v1 k2 v2 ……
&#xff1b;
hmget&#xff1a;批量的获取某个K的多个属性的值&#xff1a;hmget K k1 k2 k3……
&#xff1b;
hgetall&#xff1a;获取所有属性的值&#xff1a;hgetall K
&#xff1b;
hdel&#xff1a;删除某个属性&#xff1a;hdel K k1 k2 ……
&#xff1b;
hlen&#xff1a;统计K对应的Value总的属性的个数&#xff1a;hlen K
&#xff1b;
hexists&#xff1a;判断这个K的V中是否包含这个属性&#xff1a;hexists K k
&#xff1b;
hvals&#xff1a;获取所有属性的value&#xff1a;hvals K
&#xff1b;
lpush&#xff1a;将每个元素放到集合的左边&#xff0c;左序放入&#xff1a;lpush K e1 e2 e3……
&#xff1b;
rpush&#xff1a;将每个元素放到集合的右边&#xff0c;右序放入&#xff1a;rpush K e1 e2 e3……
&#xff1b;
lrange&#xff1a;通过下标的范围来获取元素的数据&#xff08;从左往右的下标从0开始【0 5】&#xff0c;从右往左的下标从-1开始【-5 -1】&#xff0c;∴一定是从小的到大的下标&#xff1a;lrange K 0 -1&#xff1a;所有元素&#xff09;&#xff1a;lrange K startnum endnum
&#xff1b;
llen&#xff1a;统计集合的长度&#xff1a;llen K
&#xff1b;
lpop&#xff1a;删除左边的一个元素&#xff1a;lpop K
&#xff1b;
rpop&#xff1a;删除右边的一个元素&#xff1a;rpop K
&#xff1b;
sadd&#xff1a;添加元素到Set集合中&#xff1a;sadd K e1 e2 e3 e4 e5……
&#xff1b;
smembers&#xff1a;查看Set集合的所有成员&#xff1a;smembers K
&#xff1b;
sismember&#xff1a;判断是否包含这个成员&#xff1a;sismember K e1
&#xff1b;
srem&#xff1a;删除其中某个元素&#xff1a;srem K e
&#xff1b;
scard&#xff1a;统计集合长度&#xff1a;scard K
&#xff1b;
sunion&#xff1a;取两个集合的并集&#xff1a;sunion K1 K2
&#xff1b;
sinter&#xff1a;取两个集合的交集&#xff1a;sinter K1 K2
&#xff1b;
zadd&#xff1a;用于添加元素到Zset集合中&#xff1a;zadd K score1 k1 score2 k2 ……
&#xff1b;
zrange&#xff1a;范围查询&#xff08;默认按照key的降序排列&#xff0c;使用withscores会显示key的内容&#xff09;&#xff1a;zrange K start end [withscores]
&#xff1b;
zrevrange&#xff1a;倒序查询&#xff1a;zrevrange K start end [withscores]
&#xff1b;
zrem&#xff1a;移除一个元素&#xff1a;zrem K k1
&#xff1b;
zcard&#xff1a;统计集合长度&#xff1a;zcard K
&#xff1b;
zscore&#xff1a;获取评分&#xff08;获取value对应的key&#xff09;&#xff1a;zscore K k
&#xff1b;
通过一个String对象的存储空间来构建位图&#xff0c;每位&#xff08;bit&#xff09;当然只能表示0/1。学过嵌入式的都很容易理解&#xff1a;
Redis的一个String最大为512MB&#xff08;512MB也就是2^(9&#43;10&#43;10)Byte
&#xff0c;再*8
换算后为2^(9&#43;10&#43;10&#43;3)bit
&#xff0c;换句话说&#xff0c;Redis的String是32位的&#xff0c;不是64位或者8位16位。32位&#xff08;西门子PLC称之VW&#xff0c;双字&#xff09;&#61;4字节&#xff08;西门子PLC称之VB&#xff0c;字节&#xff09;。
和数组的下标一样&#xff0c;BitMap也是从0开始的&#xff08;不需要关心大小端的问题&#xff09;&#xff0c;使用时&#xff0c;每一位默认都&#61;0&#xff0c;也可以直接操作使得置0和置1。C语言可以直接操作寄存器的好处就体现出来了&#xff01;&#xff01;&#xff01;如果使用位图的某一位来对应用户id&#xff0c;读取数据时&#xff0c;发现用户id就将该id对应的的那一位置位&#xff0c;结束后计数位图中1的个数就是UV&#xff01;&#xff01;&#xff01;也不需要SQL中DISTINCT去重&#xff01;&#xff01;&#xff01;
setbit&#xff1a;修改某一位的值&#xff1a;set K 脚标 1
&#xff1b;
getbit&#xff1a;查看某一位的值&#xff1a;getbit K 角标
&#xff1b;
bitcount&#xff1a;统计位图中1的个数&#xff08;2个脚标是字节数&#xff09;&#xff1a;bitcount K startnum endnum
&#xff1b;
bitop&#xff1a;位图的按位运算&#xff08;and与、or或、not取反、xor异或&#xff09;&#xff1a;bitop and bit3 bit1 bit2
是把bit1和bit2相与的结果放到bit3&#xff1b;
对&#xff01;&#xff01;&#xff01;没看错&#xff0c;就是2个Log。
HyperLogLog类似Set集合&#xff0c;用于实现数据的去重&#xff0c;但是底层实现原理不同&#xff0c;适合于大数据量的情况下使用&#xff08;存在误差率&#xff09;。
pfadd&#xff1a;添加元素&#xff1a;pfadd K e1 e2 e3......
&#xff1b;
pfcount&#xff1a;统计个数&#xff1a;pfcount K
&#xff1b;
pfmerge&#xff1a;实现集合合并&#xff1a;pfmerge pfrs K1 K2......
&#xff1b;
随便找个Redis低版本的试试&#xff0c;测试用&#xff0c;哪个版本都差不多。
搞到手的是个Zip包&#xff0c;和常规的软件一样&#xff0c;解压缩就能用。。。笔者选择解压到C盘&#xff0c;路径纯英文即可。里边有这些玩意儿&#xff1a;
目录/文件 | 备注 |
---|---|
redis-benchmark.exe | redis的性能测试工具 |
redis-check-aof.exe | aof文件的检查和修复工具 |
redis-check-dump.exe | rdb文件的检查和修复工具 |
redis-cli.exe | client 客户端访问命令 |
redis-server.exe | 服务器启动程序 |
redis.window.conf | 配置文件&#xff0c;这是个文本文件 |
当然是先启动server才能启动client。。。先双击redis-server.exe&#xff0c;首次使用Win10会阻挠&#xff0c;需要同意使用网络&#xff1a;
发现Redis使用的是6379
端口。如果服务端闪退&#xff0c;就搞个bat脚本强制按照配置文件的内容来启动&#xff1a;
redis-server.exe redis.windows.conf
这个脚本需要放到解压的文件夹里才能正常使用&#xff0c;都懂的。。。
双击redis-cli.exe可以启动客户端&#xff1a;
很“智能”&#xff0c;刚输入set就提醒可以修改后边的参数。。。比shell体验好多了。。。
127.0.0.1:6379> set s1 hadoop
OK
127.0.0.1:6379> keys *
1) "s1"
127.0.0.1:6379> set s2 hive
OK
127.0.0.1:6379> keys *
1) "s1"
2) "s2"
127.0.0.1:6379> get s1
"hadoop"
127.0.0.1:6379> get s2
"hive"
127.0.0.1:6379>
keys *
就是SQL中的SELECT*
。
这年头连SQLite都有很多客户端&#xff0c;Redis当然也有很多种客户端&#xff08;Redis Desktop Manager、RedisStudio、RedisClient等&#xff09;&#xff0c;笔者随便玩玩&#xff1a;
正常的下一步安装。。。
选用连接本机&#xff08;localhost
就是127.0.0.1
&#xff09;&#xff0c;之后就出现了和SQLite Studio的差不多的树形结构&#xff1a;
可以看出Redis默认有db0~db15攻击16个数据库&#xff0c;且默认使用的是db0数据库&#xff0c;也能看到之前配置的数据。
一般是Linux用Redis&#xff0c;Windows貌似用的不多。。。
先安装到一台机再说。上传安装包&#xff1a;
cd /export/software/
rz
解包&#xff1a;
tar -zxvf redis-3.2.8.tar.gz -C /export/server/
由于Redis是地球最强的C语言写的&#xff0c;不是Java的那种跨平台通用的Jar包&#xff0c;需要编译才能用&#xff0c;使用yum安装gcc依赖以便使用gcc编译&#xff1a;
yum -y install gcc-c&#43;&#43; tcl
安装好gcc就可以编译&#xff1a;
cd /export/server/redis-3.2.8/
make
安装&#xff1a;
make PREFIX&#61;/export/server/redis-3.2.8-bin install
修改配置&#xff1a;
cp /export/server/redis-3.2.8/redis.conf /export/server/redis-3.2.8-bin/
mkdir -p /export/server/redis-3.2.8-bin/logs
mkdir -p /export/server/redis-3.2.8-bin/datas
cd /export/server/redis-3.2.8-bin/
vim redis.conf
然后小心地修改4处&#xff0c;使Redis可以使用网卡&#xff08;61行&#xff09;、后台运行&#xff08;128行&#xff09;、存储服务器日志&#xff08;163行&#xff09;、持久化数据存储&#xff08;247行&#xff09;&#xff1a;
bind node1
daemonize yes
logfile "/export/server/redis-3.2.8-bin/logs/redis.log"
dir /export/server/redis-3.2.8-bin/datas/
记得保存。
创建软连接&#xff08;类似Win的快捷方式&#xff09;以便调用及修改&#xff1a;
cd /export/server
ln -s redis-3.2.8-bin redis
配置环境变量&#xff1a;
vim /etc/profile
找个空行插入&#xff1a;
# REDIS HOME
export REDIS_HOME&#61;/export/server/redis
export PATH&#61;:$PATH:$REDIS_HOME/bin
先保存&#xff0c;再重新加载环境变量&#xff1a;
source /etc/profile
OK&#xff0c;配置完成&#xff0c;试试能不能用。
国际惯例&#xff0c;先启动服务端&#xff1a;
/export/server/redis/bin/redis-server /export/server/redis/redis.conf
当然也可以自己写个shell脚本&#xff0c;就不必这么麻烦&#xff1a;
vim /export/server/redis/bin/redis-start.sh
写上内容&#xff1a;
#!/bin/bash
REDIS_HOME&#61;/export/server/redis
$REDIS_HOME/bin/redis-server $REDIS_HOME/redis.conf
增加可执行权限&#xff1a;
chmod u&#43;x /export/server/redis/bin/redis-start.sh
由于配置了环境变量&#xff0c;任意目录都可以调用脚本&#xff1a;
[root&#64;node1 server]# cd
[root&#64;node1 ~]# redis-
redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-sentinel redis-server redis-start.sh
[root&#64;node1 ~]# redis-start.sh
启动后&#xff1a;
[root&#64;node1 ~]# ps -ef |grep redis
root 5110 1 0 17:48 ? 00:00:00 /export/server/redis/bin/redis-server node1:6379
root 5118 1772 0 17:48 pts/0 00:00:00 grep --color&#61;auto redis
可以看到相关的进程&#xff08;6379端口的进程就是Redis的服务端&#xff09;。
/export/server/redis/bin/redis-cli -h node1 -p 6379
启动后&#xff1a;
[root&#64;node1 ~]# /export/server/redis/bin/redis-cli -h node1 -p 6379
node1:6379>
同意很“智能”&#xff1a;
简单试试&#xff1a;
node1:6379> keys *
(empty list or set)
node1:6379> set s1 hadoop
OK
node1:6379> keys *
1) "s1"
node1:6379> get s1
"hadoop"
和Win10上测试的效果一致&#xff0c;安装成功。
对话框输入exit
就可以退出。
客户端可以使用命令shutdown
让服务端关闭&#xff08;注意&#xff01;&#xff01;&#xff01;是Redis客户端中输入命令&#xff0c;不是shell中shutdown关机&#xff09;。如果一定要要shell中关闭&#xff0c;可以&#xff1a;
/export/server/redis/bin/redis-cli -h node1 -p 6379 shutdown
这种方式其实也是通过客户端实现的关闭。
如果先关闭了客户端&#xff0c;也有办法关闭服务端。。。惯用的当然是先找到Redis对应的服务端的pid再kill -9&#xff08;手动2步&#xff09;。或者高端的做法&#xff08;Linux中一切皆文件&#xff0c;运行中的进程也在文件中有记录&#xff0c;直接从文件中抓获进程号即可&#xff09;&#xff1a;
kill -9 &#96;cat /var/run/redis_6379.pid&#96;
如果不是root用户&#xff0c;可能有权限级别不够的问题&#xff0c;sudo开头即可&#xff08;玩树莓派和Ubuntu那会儿好像每一句都是sudo开头。。。&#xff09;&#xff1a;
sudo cat /var/run/redis_6379.pid
可以看到进程号。
当然大部分情况下不可能手动写命令&#xff0c;用类似JDBC的方式使用编程语言自动调用命令显然更高效。下一篇讲述Jedis。